package com.linran.utils.reflection;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.fastjson.util.ParameterizedTypeImpl;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import lombok.Getter;
import lombok.Setter;
import org.junit.Test;

import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;

@Getter
@Setter
public class GenericAcquire {

    @Test
    public void superGenericTypeTest() {
        IntMap intMap = new IntMap();
        System.out.println(String.format("intMap superClass: %s", intMap.getClass().getSuperclass()));
        //获取带泛型信息父类class:HashMap<Integer,String>
        Type type = intMap.getClass().getGenericSuperclass();
        if (type instanceof ParameterizedType) {
            Stream.of(((ParameterizedType) type).getActualTypeArguments()).forEach(System.out::println);
            System.out.println(String.format("intMap rawType(原始类型): %s", ((ParameterizedType) type).getRawType()));
            System.out.println(String.format("intMap ownerType(此类型为成员类型之一): %s", ((ParameterizedType) type).getOwnerType()));
            System.out.println(String.format("intMap typeName: %s", type.getTypeName()));
        }

        System.out.println("===================newClass======================");
        HashMap<Integer, String> newClass = new HashMap<>();
        System.out.println(String.format("newClass superClass: %s", newClass.getClass().getSuperclass()));
        //获取带泛型信息父类class:HashMap<Integer,String>
        Type newType = newClass.getClass().getGenericSuperclass();
        if (newType instanceof ParameterizedType) {
            Stream.of(((ParameterizedType) newType).getActualTypeArguments()).forEach(System.out::println);
            System.out.println(String.format("newClass rawType(原始类型): %s", ((ParameterizedType) newType).getRawType()));
            System.out.println(String.format("newClass ownerType(此类型为成员类型之一): %s", ((ParameterizedType) newType).getOwnerType()));
            System.out.println(String.format("newClass typeName: %s", newType.getTypeName()));
        }

        System.out.println("===================subClass======================");
        HashMap<Integer, String> subClass = new HashMap<>() {
        };//此处多了{}，和IntMap一样为继承HashMap子类型
        System.out.println(String.format("subClass superClass: %s", subClass.getClass().getSuperclass()));
        //获取带泛型信息父类class:HashMap<Integer,String>
        Type subType = subClass.getClass().getGenericSuperclass();
        if (subType instanceof ParameterizedType) {
            Stream.of(((ParameterizedType) subType).getActualTypeArguments()).forEach(System.out::println);
            System.out.println(String.format("subClass rawType(原始类型): %s", ((ParameterizedType) subType).getRawType()));
            System.out.println(String.format("subClass ownerType(此类型为成员类型之一): %s", ((ParameterizedType) subType).getOwnerType()));
            System.out.println(String.format("subClass typeName: %s", subType.getTypeName()));
        }

        //intMap superClass: class java.util.HashMap
        //class java.lang.Integer
        //class java.lang.String
        //intMap rawType(原始类型): class java.util.HashMap
        //intMap ownerType(此类型为成员类型之一): null
        //intMap typeName: java.util.HashMap<java.lang.Integer, java.lang.String>
        //===================newClass======================
        //newClass superClass: class java.util.AbstractMap
        //K
        //V
        //newClass rawType(原始类型): class java.util.AbstractMap
        //newClass ownerType(此类型为成员类型之一): null
        //newClass typeName: java.util.AbstractMap<K, V>
        //===================subClass======================
        //subClass superClass: class java.util.HashMap
        //class java.lang.Integer
        //class java.lang.String
        //subClass rawType(原始类型): class java.util.HashMap
        //subClass ownerType(此类型为成员类型之一): null
        //subClass typeName: java.util.HashMap<java.lang.Integer, java.lang.String>
    }

    public Map<String, Integer> map = new HashMap<>();
    public List<Long> list = new ArrayList<>();
    /**
     * 1.java虽然运行时会有类型擦除，但是会保留成员变量Field的泛型信息，可以通过Field.getGenericType() 取字段的泛型。
     * 2.因为泛型的运行时擦除，对于局部变量来说, 泛型信息是无法获取的
     */
    @Test
    public void fieldGenericTest() throws NoSuchFieldException {
        GenericAcquire genericAcquire = new GenericAcquire();

        Field map = genericAcquire.getClass().getField("map");
        System.out.println(String.format("map type: %s", map.getType()));
        System.out.println(String.format("map genericType: %s", map.getGenericType()));

        Field list = genericAcquire.getClass().getField("list");
        System.out.println(String.format("list type: %s", list.getType()));
        System.out.println(String.format("list genericType: %s", list.getGenericType()));

        //map type: interface java.util.Map
        //map genericType: java.util.Map<java.lang.String, java.lang.Integer>
        //list type: interface java.util.List
        //list genericType: java.util.List<java.lang.Long>
    }

    public List<ProvinceCode> provinceCodes;
    /**
     * typeReference源码就是通过获取泛型信息，进行反序列化的
     */
    @Test
    public void typeReferenceApply() throws IOException {
//        String destr = "[{\"code\":101,\"name\":\"北京\"},{\"code\":102,\"name\":\"南京\"}]";
//        GenericAcquire genericAcquire = new GenericAcquire();
//        genericAcquire.setProvinceCodes(JSONObject.parseObject(destr, new TypeReference<>(){}));
        ObjectMapper mapper = new ObjectMapper();
        mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
//        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        String str = "{\"name\":null,\"list\":[\"asdf\",\"asdf\",\"sdfsd\"]}";
        User user = mapper.readValue(str, User.class);
    }
}

class User {
    private List<String> list;
    private String name;

    public List<String> getList() {
        return list;
    }

    public void setList(List<String> list) {
        this.list = list;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

class IntMap extends HashMap<Integer, String> {
}

enum ProvinceCode {
    /**北京*/
    BEIJING(101,"北京"),
    /**南京*/
    NANJING(102,"南京");

    ProvinceCode(int code, String name) {
        this.code = code;
        this.name = name;
    }

    private int code;
    private String name;
}